package top.lingkang.mm.orm;

import java.io.File;
import java.sql.Connection;
import java.util.List;
import java.util.Map;

/**
 * 对表数据进行正删改查，若要更新更复杂的sql，请使用mapper.xml进行编写
 *
 * @Author lingkang
 * @Date 2024/3/1 10:20
 */
public interface MapperManage {
    /**
     * 返回查询条件，只能执行查询。
     * 例子：
     * <pre>
     * {@code
     *     QueryWrapper<UserEntity> query = mapperManage.createQuery(
     *             "select * from t_user where id>#{id}",
     *             UserEntity.class);
     *     query.addParam("id", 2);
     *     List<UserEntity> list = query.getList();
     *     System.out.println(list);
     * }
     * </pre>
     *
     * @param sql         mybatis 语法的sql，例如 select * from t_user where id=#{id}
     * @param resultClass 接收查询结果的类型
     * @param <T>         接收查询结果类
     * @return 查询包装
     */
    <T> QueryWrapper<T> createQuery(String sql, Class<T> resultClass);

    /**
     * 返回查询条件，只能执行查询。
     * 例子：
     * <pre>
     * {@code
     *     QueryWrapper<UserEntity> query = mapperManage.createQuery(
     *             UserEntity.class,
     *             "select * from t_user where id>#{id}"
     *             );
     *     query.addParam("id", 2);
     *     List<UserEntity> list = query.getList();
     *     System.out.println(list);
     * }
     * </pre>
     *
     * @param resultClass 接收查询结果的类型
     * @param sql         mybatis 语法的sql，例如 select * from t_user where id=#{id}
     * @param <T>         接收查询结果类
     * @return 查询包装
     * @since 1.0.6
     */
    <T> QueryWrapper<T> createQuery(Class<T> resultClass, String sql);


    /**
     * 查询结果返回map
     * <pre>
     * {@code
     * List<Map> list = mapperManage.selectToMap("select * from t_user");
     * log.info("selectToMap: {}", list);
     * }
     * </pre>
     *
     * @param sql 要执行的sql
     * @return 查询结果
     * @since 1.1.0
     */
    default List<Map> selectToMap(String sql) {
        return createQuery(sql, Map.class).getList();
    }

    /**
     * 查询结果返回map
     * <pre>
     * {@code
     *  List<Map> list = mapperManage.selectToMap(
     *      "select * from t_user where id=#{id}",
     *      MapParam.create("id", 1)
     *  );
     * log.info("selectToMap: {}", list);
     * }
     * </pre>
     *
     * @param sql   要执行的sql
     * @param param map入参
     * @return 查询结果
     * @since 1.1.0
     */
    default List<Map> selectToMap(String sql, Map<String, Object> param) {
        return createQuery(sql, Map.class).addParam(param).getList();
    }

    /**
     * 查询结果返回map
     * <pre>
     * {@code
     * Map map = mapperManage.selectToMapOne("select * from t_user where id=1");
     * log.info("selectToMapOne: {}", map);
     * }
     * </pre>
     *
     * @param sql 要执行的sql
     * @return 查询结果
     * @since 1.1.0
     */
    default Map selectToMapOne(String sql) {
        return createQuery(sql, Map.class).getOne();
    }

    /**
     * 查询结果返回map
     * <pre>
     * {@code
     * Map map = mapperManage.selectToMapOne(
     *    "select * from t_user where id=#{id}",
     *    MapParam.create("id", 1)
     * );
     * log.info("selectToMapOne: {}", map);
     * }
     * </pre>
     *
     * @param sql   要执行的sql
     * @param param map入参
     * @return 查询结果
     * @since 1.1.0
     */
    default Map selectToMapOne(String sql, Map<String, Object> param) {
        return createQuery(sql, Map.class).addParam(param).getOne();
    }

    /**
     * 返回更新条件，执行更新操作。例1 ：
     * <pre>
     * {@code
     *     UpdateWrapper update = mapperManage.createUpdate("update t_user set password=#{p} where id=#{id}");
     *     update.addParam("p", System.currentTimeMillis()).addParam("id", 1);
     *     int execute = update.execute();
     *     log.info("受影响行数: {}", execute);
     * }
     * </pre>
     * 例2：
     * <pre>
     * {@code
     *     UpdateWrapper update = mapperManage.createUpdate("insert into t_user(id,username) values (2,#{un})");
     *     update.addParam("un", "lk");
     *     int execute = update.execute();
     *     log.info("受影响行数: {}", execute);
     * }
     * </pre>
     *
     * @param sql mybatis 语法的sql，例如 update t_user set age=28 where id=#{id}
     * @return 更新包装对象
     */
    UpdateWrapper createUpdate(String sql);

    /**
     * 执行更新sql
     * <pre>
     * {@code
     *         int result = mapperManage.updateSql("update t_user set nickname='lk' where id=1");
     *         log.info("updateSql: {}", result);
     * }
     * </pre>
     *
     * @param sql 要执行的sql
     * @return 受影响行数
     * @since 1.1.0
     */
    default int updateSql(String sql) {
        return createUpdate(sql).execute();
    }

    /**
     * 执行更新sql
     * <pre>
     * {@code
     *         int result = mapperManage.updateSql(
     *                 "update t_user set nickname='lk' where id=#{id}",
     *                 MapParam.create("id", 1)
     *         );
     *         log.info("updateSql: {}", result);
     * }
     * </pre>
     *
     * @param sql   要执行的sql
     * @param param map入参
     * @return 受影响行数
     * @since 1.1.0
     */
    default int updateSql(String sql, Map<String, Object> param) {
        return createUpdate(sql).addParam(param).execute();
    }

    /**
     * 查询所有
     *
     * @param entityClass 实体对象类
     * @param <T>         实体对象类
     * @return 查询结果，不为空。无结果时返回空List
     */
    <T> List<T> selectAll(Class<T> entityClass);

    /**
     * 根据id查询数据
     *
     * @param entityClass 实体对象类
     * @param id          主键id
     * @param <T>         实体对象类
     * @return 无结果时返回 null
     */
    <T> T selectById(Class<T> entityClass, Object id);

    /**
     * 根据id判断实体对象是否存在
     *
     * @param entityClass 实体对象类
     * @param id          主键id
     * @param <T>         boolean
     * @return true 存在; false 不存在
     */
    <T> boolean existsById(Class<T> entityClass, Object id);

    /**
     * 插入数据，空值也会插入
     *
     * @param entity 实体对象
     * @return 影响的行数
     */
    int insert(Object entity);

    /**
     * 插入数据
     *
     * @param entity     实体对象
     * @param insertNull 是否插入空值，若为 false 生成的sql不带空值的列
     * @return 影响的行数
     */
    int insert(Object entity, boolean insertNull);

    /**
     * 批量插入数据
     *
     * @param list 实体对象列表
     * @return 影响的行数
     */
    <T> int insertBatch(List<T> list);

    /**
     * 根据id更新实体
     *
     * @param entity 实体对象
     * @return 影响的行数
     */
    int updateById(Object entity);

    /**
     * 根据id更新实体
     *
     * @param entity     实体对象
     * @param updateNull 是否更新空值，若为 false 生成的sql不带空值的列
     * @return 影响的行数
     */
    int updateById(Object entity, boolean updateNull);

    /**
     * 根据id删除数据
     *
     * @param entity 实体对象
     * @return 影响的行数
     */
    int deleteById(Object entity);

    /**
     * 根据id删除数据。注意，不会触发
     * {@link top.lingkang.mm.annotation.PreUpdate} 和
     * {@link top.lingkang.mm.annotation.PostUpdate} 注解方法
     *
     * @param entityClass 实体对象类
     * @param id          主键id
     * @return 影响的行数
     */
    int deleteById(Class<?> entityClass, Object id);

    /**
     * 根据id批量删除。注意，不会触发
     * {@link top.lingkang.mm.annotation.PreUpdate} 和
     * {@link top.lingkang.mm.annotation.PostUpdate} 注解方法
     *
     * @param entityClass 实体对象类
     * @param ids         id列表
     * @return 影响的行数
     */
    <T, E> int deleteByIds(Class<T> entityClass, List<E> ids);

    /**
     * 获取mapper.xml对象的接口类代理
     *
     * @param type mapper接口
     * @param <T>  mapper接口类
     * @return mapper接口代理对象
     */
    <T> T getMapper(Class<T> type);

    /**
     * 获取实体对象的查询表sql：select id, username, password from t_user
     *
     * @param entityClass 实体对象类
     * @return select id, username, password from t_user(实体对象类对应的表名)
     */
    <T> String selectTableSql(Class<T> entityClass);

    /**
     * 获取表名
     *
     * @param entityClass 实体对象类
     * @return 实体对象类对应的表名
     */
    String getTableName(Class<?> entityClass);

    /**
     * 执行sql脚本，自动处于事务中执行，出现失败时全部回滚。<br>
     * 注意，ddl级别SQL无法回滚
     *
     * @param sqlScript sql脚本内容
     */
    void executeSqlScript(String sqlScript);

    /**
     * 执行sql脚本，自动处于事务中执行，出现失败时全部回滚。<br>
     * 注意，ddl级别SQL无法回滚
     *
     * @param scriptFile sql脚本文件
     */
    void executeSqlScript(File scriptFile);

    /**
     * 获取jdbc连接，使用后请调用 close() 关闭连接。
     *
     * @return 数据库连接：Connection
     */
    Connection getConnection();

    /**
     * 获取当前连接数据库的url
     *
     * @return 例如 jdbc:mysql://localhost:3306/dbName
     * @since 1.1.0
     */
    String getUrl();

    /**
     * 获取数据库连接的协议，结果必定是小写，例如 mysql、sqlite、h2 <br/>
     * jdbc:mysql://localhost:3306/dbName --> mysql <br/>
     *
     * @return 例如 mysql、sqlite、h2 （结果必定是小写）
     * @since 1.1.0
     */
    String getProtocol();
}
